{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Ejercicio: Reparto del bote del bingo.\n",
    "Ana, Elena y Paco son aficionados al bingo. Están jugando una partida casera, en la que los cartones que han comprado han sido:\n",
    "```\n",
    "(3,10,17,18,28,44,48,54,56,61,63,65,71,72,73) -> Ana\n",
    "(4,11,13,20,21,29,30,31,50,55,58,71,78,85,90) -> Ana\n",
    "(4,12,14,16,19,33,36,42,48,57,76,78,83,85,91) -> Elena\n",
    "(6, 7,11,18,19,24,30,36,39,42,51,65,66,80,89) -> Paco\n",
    "(2, 3,10,15,17,26,27,33,76,77,78,83,84,92,95) -> Paco\n",
    "(5, 9,13,15,20,29,38,39,42,44,52,76,81,84,98) -> Paco ```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Pusieron 100 euros por cartón, así que hay 600 euros de bote, que son para el primero que cante bingo (se reparte en partes iguales si varios cantan a la vez).\n",
    "\n",
    "Tras un rato, los números que han salido son:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "vistos = [57,31,85,1,9,51,16,80,11,33,40,4,78,14]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "En este momento, por razones de fuerza mayor tienen que suspender la partida. La pregunta es: ¿cuál es el reparto justo del bote?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Solución:\n",
    "El **reparto justo** es el que asocia **a cada uno la esperanza de sus ganancias**. No es fácil calcularlas de forma exacta, pero podemos estimarlas por métodos Monte Carlo: simulando el resto de la partida un número alto de veces, y promediando.\n",
    "\n",
    "Vamos a usar diccionarios para representar la información cartón-jugador."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "cartonesOrig = {\n",
    "    (3,10,17,18,28,44,48,54,56,61,63,65,71,72,73): \"Elena\",\n",
    "    (4,11,13,20,21,29,30,31,50,55,58,71,78,85,90): \"Elena\",\n",
    "    (4,12,14,16,19,33,36,42,48,57,76,78,83,85,91): \"Ana\",\n",
    "    (6, 7,11,18,19,24,30,36,39,42,51,65,66,80,89): \"Paco\",\n",
    "    (2, 3,10,15,17,26,27,33,76,77,78,83,84,92,95): \"Paco\",\n",
    "    (5, 9,13,15,20,29,38,39,42,44,52,76,81,84,98): \"Paco\",\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Primero, construimos lo que queda de los cartones en este momento de la partida. El tipo de datos perfecto para los cartones es `set`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cartones = [(set(carton)-set(vistos), jug) for (carton, jug) in cartonesOrig.items()]\n",
    "cartones  # Mostramos los cartones ahora"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Obs**: Vemos que algunos jugadores han tenido más suerte que otros. Es por esto que ahora lo justo no es devolver a cada uno el dinero invertido.\n",
    "\n",
    "Hacemos la función principal, que devuelve un diccionario de ganancias según un futuro simulado."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import random\n",
    "from collections import defaultdict\n",
    "\n",
    "def sorteaBingo(cartones, precCarton):\n",
    "    bote = precCarton * len(cartones)\n",
    "    \n",
    "    # Como no queremos modificar el input, tenemos que hacer una copia\n",
    "    cartones = [(c.copy(), jug) for (c, jug) in cartones]\n",
    "    \n",
    "    # Organizamos la partida \n",
    "    nums = list(range(1, 100))\n",
    "    random.shuffle(nums)  # Barajamos nums\n",
    "    for n in nums:\n",
    "        # Quitamos el numero n de los cartones\n",
    "        for (carton, _) in cartones:\n",
    "            carton.discard(n)\n",
    "        # Detectamos si ya hay ganadores\n",
    "        ganadores = [jug for (carton, jug) in cartones if not carton]  # Podria contener repeticiones\n",
    "        if ganadores:\n",
    "            premio = bote / len(ganadores)\n",
    "            ganancias = defaultdict(float)\n",
    "            for jug in ganadores:\n",
    "                ganancias[jug] += premio\n",
    "            return ganancias"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ya solo falta invocar esta función tantas veces como podamos, y promediar la ganancia de cada jugador."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def estimaReparto(cartones, nSorteos, precCarton):\n",
    "    gananTotal = defaultdict(float)\n",
    "    for _ in range(nSorteos):\n",
    "        for (jug, premio) in sorteaBingo(cartones, precCarton).items():\n",
    "            gananTotal[jug] += premio / nSorteos\n",
    "    return gananTotal"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La invocamos:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rep = estimaReparto(cartones, nSorteos=40000, precCarton=100)\n",
    "print(\"El reparto justo es:\")\n",
    "for info in rep.items():\n",
    "    print(\"\\t%s --> %.2f\" % info)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
